package cn.springcloud.alibaba.auth.common.security.filter;

import cn.springcloud.alibaba.auth.common.security.CheckLoginException;
import cn.springcloud.alibaba.security.handler.MyAuthenticationFailHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CheckUserNamePasswordFilter extends GenericFilterBean {

	private final boolean postOnly = true;
	private final MyAuthenticationFailHandler failureHandler;
	private final RequestMatcher requiresAuthenticationRequestMatcher;

	public CheckUserNamePasswordFilter() {
		this.failureHandler = new MyAuthenticationFailHandler();
		this.requiresAuthenticationRequestMatcher = new AntPathRequestMatcher("/auth/login");
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		if (!this.requiresAuthentication(request)) {
			filterChain.doFilter(request, response);
			return;
		}

		if (this.postOnly && !request.getMethod().equals("POST")) {
			this.unsuccessfulAuthentication(request, response, new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()));
			return;
		}

		String username = this.obtainUsername(request);
		String password = this.obtainPassword(request);

		// 校验账户密码格式
		if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
			this.unsuccessfulAuthentication(request, response, new CheckLoginException("用户名或密码不能为空"));
			return;
		}

		if (username.length() > 30 || password.length() > 30) {
			this.unsuccessfulAuthentication(request, response, new CheckLoginException("用户名或密码长度不能超过30位"));
			return;
		}

		filterChain.doFilter(request, response);
	}

	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
		SecurityContextHolder.clearContext();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Authentication request failed: " + failed.toString(), failed);
			this.logger.debug("Updated SecurityContextHolder to contain null Authentication");
			this.logger.debug("Delegating to authentication failure handler " + this.failureHandler);
		}
		this.failureHandler.onAuthenticationFailure(request, response, failed);
	}

	protected boolean requiresAuthentication(HttpServletRequest request) {
		return this.requiresAuthenticationRequestMatcher.matches(request);
	}

	protected String obtainPassword(HttpServletRequest request) {
		return request.getParameter("password");
	}

	protected String obtainUsername(HttpServletRequest request) {
		return request.getParameter("username");
	}
}
